﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;

using System.Runtime.Serialization;
using System.Runtime.Remoting.Messaging;
using LeadTeam.Exam.Utility;

namespace LeadTeam.Exam.AdminTool
{
   public delegate  ReponseRes RequestGetDelagate(string url);
    public delegate ReponseRes RequestInvokeDelegate<P>(string url, RequestMethod method, P p);

    

    /// <summary>
    /// Request server helper class
    /// </summary>
    public class RequestHelper
    {
        /// <summary>
        /// Delegate and event for the get request
        /// </summary>
        /// <param name="e"></param>
        public delegate void RequestGetHandler (RequestEventArgs e);
        public event RequestGetHandler RequestGetCompleted;


        public delegate void RequestInvokeHandler(RequestEventArgs e);
        public event RequestInvokeHandler RequestInvokeCompleted;

        /// <summary>
        /// Fire the event for getting the result
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnRequestGetHandlerCompleted(RequestEventArgs e)
        {
            if (RequestGetCompleted != null)
             {
                 RequestGetCompleted(e);
             }
        }
        protected virtual void OnRequestInvokeHandlerCompleted(RequestEventArgs e)
        {
            if (RequestInvokeCompleted != null)
            {
                RequestInvokeCompleted(e);
            }
        }


        /// <summary>
        /// Make a get request to the target url Async
        /// </summary>
        /// <param name="url"></param>
        public  void RequestGetAsync(string url)
        {
            RequestGetDelagate del = new RequestGetDelagate(RequestGet);
            string data = "Any data you want to pass.";
            AsyncCallback callBack = new AsyncCallback(RequestGetCallBack);
            del.BeginInvoke(url, callBack, data);
        }

        /// <summary>
        ///Call back function of the  get request async
        /// </summary>
        /// <param name="asyncResult"></param>
        private  void RequestGetCallBack(IAsyncResult asyncResult)
        {
            AsyncResult result = (AsyncResult)asyncResult;
            RequestGetDelagate del = (RequestGetDelagate)result.AsyncDelegate;
            string data = (string)asyncResult.AsyncState;
            ReponseRes res = del.EndInvoke(asyncResult);

            //Fire new event
            RequestEventArgs e =new RequestEventArgs();
            e.ResponseResult =res;
            OnRequestGetHandlerCompleted(e);
        }

        /// <summary>
        /// Make a get resquest to a target url and get response
        /// </summary>
        /// <param name="url">target url </param>
        /// <returns></returns>
        public static  ReponseRes RequestGet(string url)
        {
            try
            {
                WebRequest request = WebRequest.Create(url);

                request.Headers.Add(HttpRequestHeader.Authorization, "test/123");

                request.Method = "GET";
                WebResponse response = request.GetResponse();

                HttpWebResponse httpResponse = ((HttpWebResponse)response);

                Stream dataStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(dataStream);
                string responseFromServer = reader.ReadToEnd();

                ReponseRes res = new ReponseRes();
                res.ReponseStr = responseFromServer;
                res.StateCode = httpResponse.StatusCode;
                res.StateDescription = httpResponse.StatusDescription;

                return res;
            }
            catch (WebException ex)
            {
                var errResp = ex.Response as HttpWebResponse;
                HttpStatusCode stateCode = errResp.StatusCode;

                string stateDescription = string.Empty;
                using (var stream = errResp.GetResponseStream())
                {
                    using (var sr = new StreamReader(stream))
                    {
                        stateDescription = sr.ReadToEnd();
                    }
                }

                ReponseRes res = new ReponseRes();
                res.ReponseStr = string.Empty;
                res.StateCode = stateCode;
                res.StateDescription = stateDescription;

                return res;
            }
            
        }




        public void RequestInvokeAsync<P>(string url, RequestMethod method, P p)
        {
            RequestInvokeDelegate<P> del = new RequestInvokeDelegate<P>(RequestInvoke);
            string data = "Any data you want to pass.";
            AsyncCallback callBack = new AsyncCallback(RequestInvokeCallBack);
            del.BeginInvoke(url, method, p, RequestInvokeCallBack, data);
        }

        private void RequestInvokeCallBack(IAsyncResult asyncResult)
        {
            AsyncResult result = (AsyncResult)asyncResult;
            RequestGetDelagate del = (RequestGetDelagate)result.AsyncDelegate;
            string data = (string)asyncResult.AsyncState;
            ReponseRes res = del.EndInvoke(asyncResult);

            //Fire new event
            RequestEventArgs e = new RequestEventArgs();
            e.ResponseResult = res;
            OnRequestInvokeHandlerCompleted(e);
        }

        /// <summary>
        /// Request a POST PUT or DELETE method and get response
        /// </summary>
        /// <typeparam name="P">the type need to be posted</typeparam>
        /// <param name="url">post url</param>
        /// <param name="method">method for post</param>
        /// <param name="p">post instance</param>
        /// <returns>ReponseRes</returns>
        public static  ReponseRes RequestInvoke<P>(string url, RequestMethod method, P p)
        {
            try
            {
                WebRequest request = WebRequest.Create(url);
                request.Method = method.ToString();

                //request.Headers.Add(HttpRequestHeader.Authorization, "test/123");

                string requestData = SerializeHelper.JsonSerialize<P>(p);
                byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(requestData);

                request.ContentType = "application/json;charset=utf-8";
                request.ContentLength = byteArray.Length;
                Stream dataStream = request.GetRequestStream();

                dataStream.Write(byteArray, 0, byteArray.Length);
                dataStream.Close();

                WebResponse response = request.GetResponse();

                HttpWebResponse httpResponse = ((HttpWebResponse)response);

                dataStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(dataStream);
                string responseFromServer = reader.ReadToEnd();

                reader.Close();
                dataStream.Close();
                response.Close();

                ReponseRes res = new ReponseRes();
                res.ReponseStr = responseFromServer;
                res.StateCode = httpResponse.StatusCode;
                res.StateDescription = httpResponse.StatusDescription;

                return res;
            }
            catch(WebException ex)
            {
                 var errResp = ex.Response as HttpWebResponse;
                HttpStatusCode stateCode=  errResp.StatusCode;
                
                string stateDescription = string.Empty;
                using (var stream = errResp.GetResponseStream())
                {
                    using (var sr = new StreamReader(stream))
                    {
                        stateDescription = sr.ReadToEnd();
                    }
                }

                ReponseRes res = new ReponseRes();
                res.ReponseStr = string.Empty;
                res.StateCode = stateCode;
                res.StateDescription = stateDescription;

                return res;
            }
        }

        public static ReponseRes RequestInvoke(string url, RequestMethod method)
        {
            try
            {
                WebRequest request = WebRequest.Create(url);
                request.Method = method.ToString();

                //request.Headers.Add(HttpRequestHeader.Authorization, "test/123");

                //string requestData = SerializeHelper.JsonSerialize<P>(p);
                //byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(requestData);

                request.ContentType = "application/json;charset=utf-8";
                //request.ContentLength = byteArray.Length;
                Stream dataStream = request.GetRequestStream();

                //dataStream.Write(byteArray, 0, byteArray.Length);
                dataStream.Close();

                WebResponse response = request.GetResponse();

                HttpWebResponse httpResponse = ((HttpWebResponse)response);

                dataStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(dataStream);
                string responseFromServer = reader.ReadToEnd();

                reader.Close();
                dataStream.Close();
                response.Close();

                ReponseRes res = new ReponseRes();
                res.ReponseStr = responseFromServer;
                res.StateCode = httpResponse.StatusCode;
                res.StateDescription = httpResponse.StatusDescription;

                return res;
            }
            catch (WebException ex)
            {
                var errResp = ex.Response as HttpWebResponse;
                HttpStatusCode stateCode = errResp.StatusCode;

                string stateDescription = string.Empty;
                using (var stream = errResp.GetResponseStream())
                {
                    using (var sr = new StreamReader(stream))
                    {
                        stateDescription = sr.ReadToEnd();
                    }
                }

                ReponseRes res = new ReponseRes();
                res.ReponseStr = string.Empty;
                res.StateCode = stateCode;
                res.StateDescription = stateDescription;

                return res;
            }
        }

    }
}
